#!/usr/bin/env python
"""
PyLink-SR (Python Linked Software Radio System)
(c) Bob Cowdery (G3UKB) 2008

File: dsp_main.py
Date: August 2008

This program is free software; you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation; either version 2 of the License, or
(at your option) any later version.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program; if not, write to the Free Software
Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA

The author can be reached by email at

bob@g3ukb.co.uk

================================================================================
Module Description:

This is the common jack instantiator.
This will start the appropriate jack services on a client or server

"""

#-------------------------------------------------------------------------------
# System imports
import logging
import sys
import os
from os import kill
import signal
import subprocess
import Pyro.core
import Pyro.naming
    
# Application imports
import defs
import config_service as config
import logger_service as logger

#===============================================================================
# Instantiate jack services
class JackInvoke():
    
    #---------------------------------------------------------------------------
    def __init__(self):
        if issubclass(JackInvoke, Pyro.core.ObjBase):
            Pyro.core.ObjBase.__init__(self)
        
        # Get us a logger
        self.logger = logging.getLogger('pylink.logger')
        
        self.daemon = None
        self.net_client = None
        self.alsa_out = None
        self.alsa_in = None

    #---------------------------------------------------------------------------
    def terminate(self):
        # Kill the jackd processes if we started them
        #self.logger.info('Terminating processes')
        if config.start_jack():
            if self.daemon:
                self.wait('jackd', self.daemon)
            if self.net_client:
                self.wait('net_client', self.net_client)
            if self.alsa_out:
                self.wait('alsa_out', self.alsa_out)
            if self.alsa_in:
                self.wait('alsa_in', self.alsa_in)
                     
    #---------------------------------------------------------------------------           
    def wait(self, name, proc):
        pid = proc.pid
        self.logger.info("Terminating [" + name + ']')
        kill(pid, signal.SIGTERM)
        # We must wait or it will get zombified and then jackd still thinks it's running
        proc.wait()
        self.logger.info("Terminated [" + name + ']')
      
    #---------------------------------------------------------------------------
    def start_deamon(self):   
        #-----------------------------------------------------------------------
        # Start jackd if required
        # Yes, you can start it all manually if required
        # A daemon is started on one or both machines
        # The master interfaces with the main audio card
        # The slave receives data from the network
        if config.start_jack():
            mode = config.mode()
            master_backend = config.master_backend()
            slave_backend = config.slave_backend()
            master_device = config.master_device()
            rate = config.smpl_rate()
            frames = config.frames()
            periods = config.periods()
            if mode == 'slave':
              # We are the slave machine in a netjack network
              self.daemon = subprocess.Popen(['jackd', '-d' + slave_backend])
            else:
              # We are standalone or the master machine in a netjack network and talk to the primary soundcard
              #  jackd -d alsa -d hw:0 -r 48000 -p 512 -n 16  
              self.daemon = subprocess.Popen(['jackd', '-d' + master_backend, '-d' + master_device, '-r' + str(rate), '-p' + str(frames), '-n' + str(periods)]) 
            
    #---------------------------------------------------------------------------
    def start_net_client(self):
        #-----------------------------------------------------------------------
        # Start the client
        # This is started on the master to ship data over the network
        if config.start_jack():
            slave_host=config.slave_host()
            #self.net_client = subprocess.Popen(['jacknet_client', '-p ' + slave_host])
            # For some obscure reason we have to start it like this or it gets rubbish parameters
            self.net_client = subprocess.Popen('jacknet_client -p ' + slave_host, shell=True)           
    
    #---------------------------------------------------------------------------
    def start_alsa_out(self):
        #-----------------------------------------------------------------------
        # Start the alsa_out process
        # This is started on the slave where we need to output to the local sound card
        # Note that this is not clock synchronised
        if config.start_jack():
            slave_device = config.slave_device()
            frames = config.frames()
            catch_factor=config.catch_factor()
            max_diff=config.max_diff()           
            #self.alsa_out = subprocess.Popen(['alsa_out', '-d' + slave_device, '-f' + str(catch_factor), '-m' + str(max_diff)])
            # For some reason the -f and -m params really mess up the output
            self.alsa_out = subprocess.Popen(['alsa_out', '-d' + slave_device])
            
     #---------------------------------------------------------------------------
    def start_alsa_in(self):
        #-----------------------------------------------------------------------
        # Start the alsa_in process
        # This is started on the slave where we need to input from the local sound card
        # Note that this is not clock synchronised
        if config.start_jack():
            slave_device = config.slave_device()
            frames = config.frames()
            catch_factor=config.catch_factor()
            max_diff=config.max_diff()           
            self.alsa_in = subprocess.Popen(['alsa_in', '-d' + slave_device, '-f' + str(catch_factor), '-p' + str(frames), '-m' + str(max_diff)])
            